package com.amos.doublewriterconsistence.thread;

import com.amos.doublewriterconsistence.request.Request;
import com.amos.doublewriterconsistence.request.RequestQueue;
import com.amos.doublewriterconsistence.request.impl.InventoryCacheRequest;
import com.amos.doublewriterconsistence.request.impl.InventoryDBRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;

/**
 * Copyright © 2020 心情如水. All rights reserved.
 *
 * @Project: rabbitmq
 * @ClassName: RequestThread
 * @Package: com.amos.common.thread
 * @author: QIXIAOWEI
 * @Description: 执行请求的工作线程
 * <p/>
 * 线程和队列进行绑定，然后再线程中处理对应的业务逻辑
 * @date: 2020/2/19 0021 下午 21:34
 * @Version: V1.0
 */
public class RequestThread implements Callable<Boolean> {

    public final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     *  自己监控的内存队列
     *
     ******************************************************************************************************
     * ArrayBlockingQueue 是数组实现的线程安全的有界的阻塞队列
     * 线程安全是指，ArrayBlockingQueue内部通过“互斥锁”保护竞争资源，实现了多线程对竞争资源的互斥访问。
     * 而有界，则是指ArrayBlockingQueue对应的数组是有界限的。
     * 阻塞队列，是指多线程访问竞争资源时，当竞争资源已被某线程获取时，其它要获取该资源的线程需要阻塞等待；
     * 而且，ArrayBlockingQueue是按 FIFO（先进先出）原则对元素进行排序，元素都是从尾部插入到队列，从头部开始返回。
     *
     *
     * ArrayBlockingQueue是数组实现的线程安全的有界的阻塞队列，常用于生产者-消费者模式，能够容纳指定个数的元素，
     * 当队列满时不能再放新的元素，当队列为空时不能取出元素，此时相应的生产者或者消费者线程往往会挂起。
     * 本类是一种先进先出(FIFO)的队列结构，内部通过数组实现
     ******************************************************************************************************
     *
     */
    private ArrayBlockingQueue<Request> queue;

    public RequestThread(ArrayBlockingQueue<Request> queue) {
        this.queue = queue;
    }

    /**
     * 方法中执行具体的业务逻辑
     * @return
     * @throws Exception
     */
    @Override
    public Boolean call() throws Exception {
        this.logger.info("调用Callable的call()方法进行逻辑处理开始！");
        try {
            while (true) {
                this.logger.info("**************如果队列满了，或者是空的，那么都会在执行操作的时候，阻塞住**************");
                /**
                 * ArrayBlockingQueue
                 * Blocking就是说明，如果队列满了，或者是空的，那么都会在执行操作的时候，阻塞住
                 */
                Request request = this.queue.take();
                this.logger.info("工作线程处理请求--缓存队列执行+++++++++++++++++，{}", request.getInventoryId());

                /**
                 *  执行这个request操作
                 * InventoryDBRequest类的process操作，实现===数据更新操作
                 * 1. 先删除缓存中的数据
                 * 2. 再更新数据库中的数据
                 *
                 * InventoryCacheRequest类的process操作，实现===处理缓存的业务请求（读取数据的代码逻辑）
                 * 1、在数据库中查询出对应的数据，然后将数据写入到缓存中
                 *  * 由此我们需要获取库存的id，根据id获取库存的数据
                 * 2、然后将库存数据写入到缓存中 数据中的key是库存ID的标识，value是查询出来的缓存数据
                 */
                request.process();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        this.logger.info("call直接停止了，导致请求的线程全部hodl在这里了");
        return Boolean.TRUE;
    }
}